/*
 * Copyright (c) 2002 David Corbin and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    David Corbin - Add support for creating depot "connections" in all cases
 *    Boris Pruessmann - Tweaked behavior
 */
package net.sourceforge.perforce.ui.wizards;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IClientForm;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.internal.api.FolderRepositoryRelation;
import net.sourceforge.perforce.ui.IPerforceUIConstants;
import net.sourceforge.perforce.ui.MicroPlugin;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;

/**
  * @version $Revision: 165 $
  * @author  <a href="mailto:dcorbin@users.sourceforge.net">David Corbin</a>
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
class ConnectProjectPage extends PerforceWizardPage
{	
	// --------------------------------------------------------------------------- Private Variables
	
	/** Combo box containing the servers. */
	private Combo serverCombo;
	/** Text fiel showing the project's location. */
	private Text location;
	/** Location Browse button */
	private Button locationButton;
	/** Label showing additional information. */
	private Label projectLocationWarning;
	/** Stores the current project path. */
	private IPath currentProjectPath;
	/** Stores the current folder relation. */
	private FolderRepositoryRelation relation;
	/** Stores the MicroPlugin instance. */
	private MicroPlugin plugin;

	// -------------------------------------------------------------------------------- Constructors
	
	/** Constructor for ConnectProjectPage.
	  * 
	  * @param plugin the MicroPlugin instance.
	  * @param projectLocation the project location.
	  */
	ConnectProjectPage(MicroPlugin plugin, IPath projectLocation)
	{
		super(
			"mappingPage",
			Policy.bind("ConnectProjectPage.title"),                                   //$NON-NLS-1$
			plugin.getImageDescriptor(IPerforceUIConstants.IMG_WIZBAN_SHARE));

		this.plugin = plugin;
		this.currentProjectPath = projectLocation;
	}

	// ------------------------------------------------------------------------------ Public Methods

	/** @see WizardPage#setErrorMessage(String) */
	public void setErrorMessage(String msg)
	{
		super.setErrorMessage(msg);
		setPageComplete(msg == null);
	}

	/** Called to check whether the page allows finish or not.
	  * 
	  * @return true if page can finish.
	  */
	public boolean canFinish()
	{
		return getErrorMessage() == null;
	}
	
	/** @see WizardPage#createControl(Composite) */
	public void createControl(Composite parent)
	{
		Composite composite = createComposite(parent, 3);
		
		// Perforce Server
		createLabel(composite, Policy.bind("ConnectProjectPage.perforceServer"));      //$NON-NLS-1$
		serverCombo = createCombo(composite);
		GridData data = (GridData) serverCombo.getLayoutData();
		data.horizontalSpan = 2;

		// Project Location
		createLabel(composite, Policy.bind("ConnectProjectPage.projectLocation"));     //$NON-NLS-1$
		location = createTextField(composite);
		location.setEditable(false);	
		locationButton = 
			createButton(composite, Policy.bind("ConnectProjectPage.browse"));         //$NON-NLS-1$

		// Project Location Warning
		projectLocationWarning = createCenteredLabel(composite);
		data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
		projectLocationWarning.setLayoutData(data);
		data.horizontalSpan = 3;
		data.horizontalAlignment = GridData.CENTER;
		data.heightHint = 50;
				
		linkProjectLocationControls(parent);
	
		initializeValue();
		serverCombo.setFocus();
		
		setControl(composite);		
	}
	
	/** Call this method to retrieve the project's "new" location.
	  * 
	  * @return the new location of the project.
	  */
	public IPath getProjectLocation() 
	{
		return new Path(location.getText());
	}

	/** Call this method to retrieve the currently selected Perforce server.
	  * 
	  * @return the selected Perforce Server.
	  */
	public IPerforceServer getServer()
	{
		IPerforceServer[] servers = PerforceCorePlugin.getServerManager().getPerforceServers();
		return servers[serverCombo.getSelectionIndex()];
	}
		
	// ----------------------------------------------------------------------------- Private Methods
	
	/** Initializes the values of the controls. */
	private void initializeValue() 
	{
		// Perforce Server
		IPerforceServer[] servers = PerforceCorePlugin.getServerManager().getPerforceServers();
		for (int i = 0; i < servers.length; i++)
		{
			serverCombo.add(servers[i].getUniqueName());
		}
		serverCombo.select(0);
		
		// Perforce Location
		location.setText(currentProjectPath.toOSString());
	}
	
	/** Call this method to retrieve the client form of the currently selected server.
	  * 
	  * @return the client form.
	  * 
	  * @throws PerforceException in case of an error.
	  */
	private IClientForm getClientForm()
		throws PerforceException
	{
		return getServer().getClientForm();
	}
	
	/** Called to adjust the values of the page's controls.
	  * 
	  * @param pathName the current project path.
	  */
	private void adjustControls(String pathName)		
	{
		try
		{
			if (pathName.equals(""))
			{
				adjustControls(FolderRepositoryRelation.OUTSIDE_ROOT);
				return;
			}
	
			IPath path = new Path(pathName);
			IPath workspaceRoot = plugin.getWorkspaceRoot().getLocation();
	
			projectLocationWarning.setText(moveMessageText(path));
			
			if (path.isPrefixOf(workspaceRoot))
			{
				setErrorMessage(Policy.bind("ConnectProjectPage.cannotBeParent"));     //$NON-NLS-1$
				return;
			}
			
			adjustControls(getServer().determineFolderPosition(pathName));
		}
		catch (PerforceException e)
		{
			PerforceUIPlugin.log(e.getStatus());
		}
	}
	
	/** Called to adjust the values of the page's controls based on the given relation.
	  * 
	  * @param newRelation the relation of the project path to the client spec.
	  * 
	  * @throws PerforceException in case of an error.
	  */
	private void adjustControls(FolderRepositoryRelation newRelation)
		throws PerforceException
	{
		if (newRelation == FolderRepositoryRelation.IN_VIEW)
		{
			setErrorMessage(null);
		}
		else
		if (newRelation == FolderRepositoryRelation.IN_REPOSITORY)
		{
			setErrorMessage(null);
			projectLocationWarning.setText(
				Policy.bind("ConnectProjectPage.projectInDepot"));                     //$NON-NLS-1$
		}
		else
		if (newRelation == FolderRepositoryRelation.OUTSIDE_ROOT)
		{			
			setErrorMessage(
				Policy.bind(
					"ConnectProjectPage.notBeneathRoot",                               //$NON-NLS-1$
					getClientForm().getRoot()));
		}
		else 
		if (newRelation == FolderRepositoryRelation.UNDER_ROOT)
		{
			setErrorMessage(Policy.bind("ConnectProjectPage.requiresManualEditing"));  //$NON-NLS-1$
		}
		else
		{
			setErrorMessage(Policy.bind("ConnectProjectPage.unexpectedResponse"));     //$NON-NLS-1$
		}
			
	}

	/** Returns the text to be shown when the project is moved.
	  * 
	  * @param path the new path.
	  * @return String the text.
	  */
	private String moveMessageText(IPath path)
	{
		if (path.equals(currentProjectPath))
		{
			return "";                                                                //$NON-NLS-1$
		}
		
		return Policy.bind("ConnectProjectPage.projectWillMove");                     //$NON-NLS-1$
	}
	
	/** Call this method to link the controls' behavior.
	  * 
	  * @param parent the parent control.
	  */
	private void linkProjectLocationControls(final Composite parent) 
	{
		// Perforce Server
		serverCombo.addSelectionListener(new SelectionListener()
		{
			public void widgetDefaultSelected(SelectionEvent e) 
			{
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) 
			{
				adjustControls(location.getText());
			}

		});
		
		// Project Location
		locationButton.addSelectionListener(new SelectionListener()
		{
			public void widgetDefaultSelected(SelectionEvent event)
			{
				widgetSelected(event);
			}
			
			public void widgetSelected(SelectionEvent event)
			{	
				try
				{
					DirectoryDialog dialog = new DirectoryDialog(parent.getShell());				
					String start = getClientForm().getRoot();
					dialog.setFilterPath(start);
					
					String pathString = dialog.open();
					if (pathString != null)
					{
						IPath path = new Path(pathString).append(currentProjectPath.lastSegment());
						location.setText(path.toOSString());
					}
				}
				catch (PerforceException e)
				{
					PerforceUIPlugin.log(e.getStatus());
				}
			}
		});
		
		location.addModifyListener(new ModifyListener()
		{
			public void modifyText(ModifyEvent event)
			{
				adjustControls(location.getText());
			}
		});
	}
}
